"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                               兼容性设置                                     "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" 兼容性设置 {{{
if has("gui_running")
    let g:isGUI = 1
else
    let g:isGUI = 0
endif
" Identify platform {
    silent function! OSX()
        return has('macunix')
    endfunction
    silent function! LINUX()
        return has('unix') && !has('macunix') && !has('win32unix')
    endfunction
    silent function! WINDOWS()
        return  (has('win32') || has('win64'))
    endfunction
" }
" Basics {
    set nocompatible              " be iMproved, required
    if (OSX() || LINUX())
        " set shell=/bin/sh
        set shell=/bin/zsh
    elseif has('win32unix')
        set shell=/bin/bash
        " TODO: windows 下启用会出错.
    else
    endif
" }
if WINDOWS()
    " set runtimepath=$HOME/.vim,$VIM/vimfiles,$VIMRUNTIME
    set runtimepath=$HOME/.vim,$VIMRUNTIME
endif
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                   vim-plug                                   "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" vim-plug {{{
" 自动安装 vim-plug TODO: 兼容 windows
if empty(glob('~/.vim/autoload/plug.vim'))
  silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
    \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
" Windows 下需要手动 PlugInstall

call plug#begin('~/.vim/plugged')

" UI -----------------------------------------------------------------------{{{
Plug 'altercation/vim-colors-solarized'
Plug 'morhetz/gruvbox'
Plug 'tomasr/molokai'
" indentline
Plug 'yggdroot/indentline'
" 美化状态栏
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'
"}}}

" Text Object --------------------------------------------------------------{{{
" text-obj - a line: al
Plug 'kana/vim-textobj-line'
" text-obj - entire: ae, ie
Plug 'kana/vim-textobj-entire'
" text-obj - url: au, iu with or without tailing spaces
Plug 'jceb/vim-textobj-uri'
" 下面几个需要去查一下怎么用
Plug 'kana/vim-textobj-user'
Plug 'kana/vim-textobj-indent'
Plug 'kana/vim-textobj-syntax'
" if, af
Plug 'kana/vim-textobj-function', { 'for':['c', 'cpp', 'vim', 'java'] }
Plug 'sgur/vim-textobj-parameter'
"}}}

" Useful -------------------------------------------------------------------{{{
" 格式化插件. vim-markdown 需要这个
Plug 'godlygeek/tabular'
" 支持更多插件提供的操作的点(.)操作
Plug 'tpope/vim-repeat'
" Fold 插件
Plug 'masukomi/vim-markdown-folding', {'for':['markdown']}
" Plug 'tmhedberg/SimpylFold'
" 用来给两端插东西很方便, 用法去 https://vimawesome.com/plugin/surround-vim 看
Plug 'tpope/vim-surround'
" 文件搜索
" https://github.com/Yggdroot/LeaderF
" After running any command of LeaderF, check the value of echo g:Lf_fuzzyEngine_C, if the value is 1, it means the C extension is loaded sucessfully
if WINDOWS()
    Plug 'Yggdroot/LeaderF', { 'do': '.\install.bat' }
else
    Plug 'Yggdroot/LeaderF', { 'do': './install.sh' }
endif
"}}}

" Markdown -----------------------------------------------------------------{{{
" vim-markdown
Plug 'plasticboy/vim-markdown'
" 即时浏览
" Plug 'suan/vim-instant-markdown'
" vim 表格插件
" https://github.com/dhruvasagar/vim-table-mode
Plug 'dhruvasagar/vim-table-mode'
" markdown 大纲插件
Plug 'jszakmeister/markdown2ctags'
"}}}

" HTML ---------------------------------------------------------------------{{{
" Emmet 插件
Plug 'mattn/emmet-vim'
" html
Plug 'alvan/vim-closetag'
"}}}

" Python -------------------------------------------------------------------{{{
" python indent 插件, 解决函数头有多行的缩进问题
Plug 'vim-scripts/indentpython.vim'
"}}}


" c++ ---------------------------------------------------------------------{{{
" c++ 语法高亮
" Plug 'octol/vim-cpp-enhanced-highlight'

" Rust ---------------------------------------------------------------------{{{
Plug 'rust-lang/rust.vim'
"}}}

" Golang -------------------------------------------------------------------{{{
" https://github.com/fatih/vim-go-tutorial
" https://github.com/fatih/vim-go
" 
" Plug 'fatih/vim-go'
"}}}

" IDE ----------------------------------------------------------------------{{{
" 代码补全
" Plug 'https://gitee.com/codergege/coc.nvim.git', {'branch': 'release'}
Plug 'neoclide/coc.nvim', {'branch': 'release'}
" 用法看这里 https://github.com/tpope/vim-commentary/blob/master/doc/commentary.txt
Plug 'tpope/vim-commentary'
" 语法检查
" ctags 插件, 需要 Universal Ctags: https://github.com/universal-ctags/ctags
Plug 'ludovicchabant/vim-gutentags' " 管理 ctags
Plug 'majutsushi/tagbar'
" nerdtree
Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }
" commenter
" Plug 'scrooloose/nerdcommenter'
" auto-pairs
Plug 'jiangmiao/auto-pairs'

" Plug 'dense-analysis/ale'
" Plug 'neomake/neomake'

" Plug 'sirver/ultisnips'
Plug 'honza/vim-snippets'

" 编译运行
" https://github.com/skywind3000/asyncrun.vim/blob/master/README-cn.md
Plug 'skywind3000/asyncrun.vim'

let g:plug_timeout = 300 " Increase vim-plug timeout for YouCompleteMe.
"}}}


call plug#end()
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                             Key Mapping Settings                             "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Key Mapping Settings{{{
" 设置 leader 键
let mapleader=" "
let maplocalleader=" "

" 映射 jk -> esc, disable esc, ctrl+[
inoremap jk <esc>
vnoremap jk <esc>
" inoremap <esc> <nop>
" inoremap <c-[> <nop>

" 复制到 clipboard
" set clipboard+=unnamed
" for ubuntu
if (OSX() || LINUX())
    set clipboard+=unnamedplus
elseif (WINDOWS())
    set clipboard+=unnamed
endif
" 修复 jk 引起的粘贴 bug
set t_BE=

" 移动到行首, 行尾
nnoremap H ^
vnoremap H ^
nnoremap L $
vnoremap L $

" 插入模式将单词转为大写
inoremap uu <esc>gUawhea

" 取消搜索高亮
nmap // :noh<cr>

" 快速配置 .vimrc
if !WINDOWS() && !has('win32unix')
    nnoremap <leader>ev :vsplit ~/.vimrc<cr>
    nnoremap <leader>sv :source ~/.vimrc<cr>
    autocmd! bufwritepost .vimrc source ~/.vimrc
elseif has('win32unix')
    nnoremap <leader>ev :vsplit ~/.vim/vimrc<cr>
    nnoremap <leader>sv :source ~/.vim/vimrc<cr>
    autocmd! bufwritepost .vimrc source ~/.vim/vimrc
else
    nnoremap <leader>ev :vsplit ~\vimfiles\vimrc<cr>
    nnoremap <leader>sv :source ~\vimfiles\vimrc<cr>
    autocmd! bufwritepost vimrc source ~\vimfiles\vimrc
endif
"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                基本设置                                      "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" 基本设置{{{
set hidden
" use utf-8
set encoding=utf-8

" General recommended settings for editing "*.txt" files
set nocp et ts=4 sw=4 tw=80 ai

" 让第 80 列高亮
" set cc=80
set cc=120

" TODO: 怎么才能更好的断行呢? 还是觉得 默认的 wrap 好用.
" set linebreak

" 设置命令行的高度
set cmdheight=2

" You will have bad experience for diagnostic messages when it's default 4000.
set updatetime=300

" don't give |ins-completion-menu| messages.
set shortmess+=c

" always show signcolumns
set signcolumn=yes

" 从不备份
set nobackup
set nowritebackup

" 不产生 swap file
set noswapfile

" 不产生 un~ 文件
set noundofile

" 解决 backspace 无法使用的问题
set backspace=indent,eol,start

" 去掉错误声
set noeb

" 自动缩进
set autoindent

" tab 宽度
set tabstop=4

" 设置行号
set nu

" Show line number, cursor position
set ruler

" inc 搜索
set incsearch
"高亮搜索的关键字
set hlsearch
"搜索忽略大小写
set ignorecase

"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                   Folding                                    "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Folding{{{
" 折叠方式
" set foldmethod=syntax
" set foldmethod=marker
" ?
"set foldcolumn=4
" set foldlevel=100
"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                 UI settings                                  "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" UI settings{{{
" 设置主题
if (g:isGUI || !WINDOWS())
    " colorscheme solarized
    colorscheme gruvbox
else
    colorscheme gruvbox
    " colorscheme molokai
endif
set background=dark

" 字体
if g:isGUI
    " set guifont=Anonymous\ Pro\ for\ Powerline:h17
    " for gvim
    set guifont=Consolas:h17
endif

" 窗口最大化
if g:isGUI
    " macvim 不支持下面的写法
    autocmd GUIEnter * simalt ~x
endif

" 隐藏菜单栏, 工具栏, 滚动条
if g:isGUI
	" Toggle Menu and Toolbar
	set guioptions-=m
	set guioptions-=T
	map <silent> <c-F11> :if &guioptions =~# 'T' <Bar>
			\set guioptions-=T <Bar>
			\set guioptions-=m <bar>
		\else <Bar>
			\set guioptions+=T <Bar>
			\set guioptions+=m <Bar>
		\endif<CR>

	" remove left-hand scroll bar
	set guioptions-=L
	" remove right-hand scroll bar
	set guioptions-=r
endif

" indentline 配置
" Vim
let g:indentLine_color_term = 239

" GVim
let g:indentLine_color_gui = '#758A99'

" none X terminal
let g:indentLine_color_tty_light = 7 " (default: 4)
let g:indentLine_color_dark = 1 " (default: 2)

" Background (Vim, GVim)
let g:indentLine_bgcolor_term = 202
let g:indentLine_bgcolor_gui = '#A4E2C6'

" 当前行高亮
set cursorline
if !g:isGUI && WINDOWS()
    highlight CursorLine term=Bold cterm=Bold
endif

"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                    标签页配置                                "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" 标签页{{{
noremap <silent><leader>1 :tabn 1<cr>
noremap <silent><leader>2 :tabn 2<cr>
noremap <silent><leader>3 :tabn 3<cr>
noremap <silent><leader>4 :tabn 4<cr>
noremap <silent><leader>5 :tabn 5<cr>
noremap <silent><leader>6 :tabn 6<cr>
noremap <silent><leader>7 :tabn 7<cr>
noremap <silent><leader>8 :tabn 8<cr>
noremap <silent><leader>9 :tabn 9<cr>
noremap <silent><leader>0 :tabn 10<cr>

" make tabline in terminal mode
function! Vim_NeatTabLine()
    let s = ''
    for i in range(tabpagenr('$'))
        " select the highlighting
        if i + 1 == tabpagenr()
            let s .= '%#TabLineSel#'
        else
            let s .= '%#TabLine#'
        endif
        " set the tab page number (for mouse clicks)
        let s .= '%' . (i + 1) . 'T'
        " the label is made by MyTabLabel()
        let s .= ' %{Vim_NeatTabLabel(' . (i + 1) . ')} '
    endfor
    " after the last tab fill with TabLineFill and reset tab page nr
    let s .= '%#TabLineFill#%T'
    " right-align the label to close the current tab page
    if tabpagenr('$') > 1
        let s .= '%=%#TabLine#%999XX'
    endif
    return s
endfunc

" get a single tab name
function! Vim_NeatBuffer(bufnr, fullname)
    let l:name = bufname(a:bufnr)
    if getbufvar(a:bufnr, '&modifiable')
        if l:name == ''
            return '[No Name]'
        else
            if a:fullname
                return fnamemodify(l:name, ':p')
            else
                return fnamemodify(l:name, ':t')
            endif
        endif
    else
        let l:buftype = getbufvar(a:bufnr, '&buftype')
        if l:buftype == 'quickfix'
            return '[Quickfix]'
        elseif l:name != ''
            if a:fullname
                return '-'.fnamemodify(l:name, ':p')
            else
                return '-'.fnamemodify(l:name, ':t')
            endif
        else
        endif
        return '[No Name]'
    endif
endfunc

" get a single tab label
function! Vim_NeatTabLabel(n)
    let l:buflist = tabpagebuflist(a:n)
    let l:winnr = tabpagewinnr(a:n)
    let l:bufnr = l:buflist[l:winnr - 1]
    return Vim_NeatBuffer(l:bufnr, 0)
endfunc

" get a single tab label in gui
function! Vim_NeatGuiTabLabel()
    let l:num = v:lnum
    let l:buflist = tabpagebuflist(l:num)
    let l:winnr = tabpagewinnr(l:num)
    let l:bufnr = l:buflist[l:winnr - 1]
    return Vim_NeatBuffer(l:bufnr, 0)
endfunc

" setup new tabline, just like %M%t in macvim
set tabline=%!Vim_NeatTabLine()
set guitablabel=%{Vim_NeatGuiTabLabel()}
"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                               Plugin settings                                "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Plugin settings{{{

"" vim-gutentags ----------------------------------------------------------------------{{{
" gutentags 搜索工程目录的标志，碰到这些文件/目录名就停止向上一级目录递归
let g:gutentags_project_root = ['.root', '.svn', '.git', '.hg', '.project', '.sln']

" 所生成的数据文件的名称
let g:gutentags_ctags_tagfile = '.tags'

" 将自动生成的 tags 文件全部放入 $HOME/.cache/tags 目录中，避免污染工程目录
let s:vim_tags = expand('$HOME/.cache/tags')
let g:gutentags_cache_dir = s:vim_tags

" 配置 ctags 的参数
let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extra=+q']
let g:gutentags_ctags_extra_args += ['--c++-kinds=+px']
let g:gutentags_ctags_extra_args += ['--c-kinds=+px']

" 检测 ~/.cache/tags 不存在就新建
if !isdirectory(s:vim_tags)
   silent! call mkdir(s:vim_tags, 'p')
endif
"" Tagbar ----------------------------------------------------------------------{{{
set tags=./.tags;,.tags " 这样在源码的顶层目录放一个 .ctags 文件即可
nmap <silent> <Leader>tag :TagbarToggle<CR>
map <silent> <c-g> :TagbarToggle<CR>
let g:tagbar_ctags_bin = 'ctags'
let g:tagbar_sort = 0

" 支持 css
let g:tagbar_type_css = {
\ 'ctagstype' : 'Css',
    \ 'kinds'     : [
        \ 'c:classes',
        \ 's:selectors',
        \ 'i:identities'
    \ ]
\ }

" 支持 typescript
let g:tagbar_type_typescript = {
  \ 'ctagsbin' : 'tstags',
  \ 'ctagsargs' : '-f-',
  \ 'kinds': [
    \ 'e:enums:0:1',
    \ 'f:function:0:1',
    \ 't:typealias:0:1',
    \ 'M:Module:0:1',
    \ 'I:import:0:1',
    \ 'i:interface:0:1',
    \ 'C:class:0:1',
    \ 'm:method:0:1',
    \ 'p:property:0:1',
    \ 'v:variable:0:1',
    \ 'c:const:0:1',
  \ ],
  \ 'sort' : 0
\ }

"打开文件自动 打开tagbar
autocmd BufReadPost *.cpp,*.c,*.h,*.hpp,*.cc,*.cxx,*.py,*.js,*.ts,*.rs,*.go call tagbar#autoopen()
"}}}
" coc.nvim ------------------------------------------------------------------{{{
" airline status 支持 coc-status
let g:airline#extensions#coc#enabled = 1
let airline#extensions#coc#error_symbol = 'E:'
"* change warning symbol: >
let airline#extensions#coc#warning_symbol = 'W:'
"* change error format: >
let airline#extensions#coc#stl_format_err = '%E{[%e(#%fe)]}'
"* change warning format: >
let airline#extensions#coc#stl_format_warn = '%W{[%w(#%fw)]}'
" set updatetime=100

" Use tab for trigger completion with characters ahead and navigate.
" Use command ':verbose imap <tab>' to make sure tab is not mapped by other plugin.
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

" 适用 alt+/ 重新打开补全 list
inoremap <silent><expr> <m-/> coc#refresh()

" Use <cr> to confirm completion, `<C-g>u` means break undo chain at current position.
" Coc only does snippet and additional edit on confirm.
" inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
" Or use `complete_info` if your vim support it, like:
inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>"

" Use `[g` and `]g` to navigate diagnostics
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)

" Remap keys for gotos
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)

" Use K to show documentation in preview window
nnoremap <silent> K :call <SID>show_documentation()<CR>

function! s:show_documentation()
  if (index(['vim','help'], &filetype) >= 0)
    execute 'h '.expand('<cword>')
  else
    call CocAction('doHover')
  endif
endfunction

" Highlight symbol under cursor on CursorHold 
autocmd CursorHold * silent call CocActionAsync('highlight')

" Remap for rename current word
nmap <leader>rn <Plug>(coc-rename)

" Remap for format selected region
xmap <leader>f  <Plug>(coc-format-selected)
nmap <leader>f  <Plug>(coc-format-selected)

augroup mygroup
  autocmd!
  " Setup formatexpr specified filetype(s).
  autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
  " Update signature help on jump placeholder
  autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
augroup end

" ?
" Remap for do codeAction of selected region, ex: `<leader>aap` for current paragraph
xmap <leader>a  <Plug>(coc-codeaction-selected)
nmap <leader>a  <Plug>(coc-codeaction-selected)

" Remap for do codeAction of current line
nmap <leader>ac  <Plug>(coc-codeaction)
" Fix autofix problem of current line
nmap <leader>qf  <Plug>(coc-fix-current)

" Create mappings for function text object, requires document symbols feature of languageserver.
xmap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap if <Plug>(coc-funcobj-i)
omap af <Plug>(coc-funcobj-a)

" Use <TAB> for select selections ranges, needs server support, like: coc-tsserver, coc-python
nmap <silent> <TAB> <Plug>(coc-range-select)
xmap <silent> <TAB> <Plug>(coc-range-select)

" Use `:Format` to format current buffer
command! -nargs=0 Format :call CocAction('format')

" Use `:Fold` to fold current buffer
command! -nargs=? Fold :call     CocAction('fold', <f-args>)

" use `:OR` for organize import of current buffer
command! -nargs=0 OR   :call     CocAction('runCommand', 'editor.action.organizeImport')

" Add status line support, for integration with other plugin, checkout `:h coc-status`
set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}

" Using CocList
" Show all diagnostics
nnoremap <silent> <space>a  :<C-u>CocList diagnostics<cr>
" Manage extensions
nnoremap <silent> <space>e  :<C-u>CocList extensions<cr>
" Show commands
nnoremap <silent> <space>c  :<C-u>CocList commands<cr>
" Find symbol of current document
nnoremap <silent> <space>o  :<C-u>CocList outline<cr>
" Search workspace symbols
nnoremap <silent> <space>s  :<C-u>CocList -I symbols<cr>
" Do default action for next item.
nnoremap <silent> <space>j  :<C-u>CocNext<CR>
" Do default action for previous item.
nnoremap <silent> <space>k  :<C-u>CocPrev<CR>
" Resume latest coc list
nnoremap <silent> <space>p  :<C-u>CocListResume<CR>

" coc-snippets 使用 tab
inoremap <silent><expr> <TAB>
      \ pumvisible() ? coc#_select_confirm() :
      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

inoremap <silent><expr> <c-j>
      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ ""

let g:coc_snippet_next = '<tab>'
let g:coc_snippet_next = '<C-j>'
let g:coc_snippet_prev = '<C-k>'
"}}}

" SimpleFold ------------------------------------------------------------------{{{
" want to see the docstrings for folded code
" let g:SimpylFold_docstring_preview=1
"}}}

" Nerdtree --------------------------------------------------------------------{{{
"" 不显示这些文件
let NERDTreeIgnore=['\.pyc$', '\~$', 'node_modules'] "ignore files in NERDTree

" nerdcommeter set up
" Add spaces after comment delimiters by default
let g:NERDSpaceDelims = 1

" Use compact syntax for prettified multi-line comments
let g:NERDCompactSexyComs = 1

" Align line-wise comment delimiters flush left instead of following code indentation
let g:NERDDefaultAlign = 'left'

" Set a language to use its alternate delimiters by default
let g:NERDAltDelims_java = 1

" Add your own custom formats or override the defaults
let g:NERDCustomDelimiters = { 'c': { 'left': '/**','right': '*/' } }

" Allow commenting and inverting empty lines (useful when commenting a region)
let g:NERDCommentEmptyLines = 1

" Enable trimming of trailing whitespace when uncommenting
let g:NERDTrimTrailingWhitespace = 1

" 新打开文件(标签页)时保持 nerdtree 打开
let NERDTreeQuitOnOpen=0

" nerdtree toggle
map <C-n> :NERDTreeToggle<CR>
" 调整分割窗口大小, 影响 w 速度, 取消
" 水平
"nmap    wk  :resize +3<CR>
"nmap    wj  :resize -3<CR>
" 垂直
"nmap    wh  :vertical resize -3<CR>
"nmap    wl  :vertical resize +3<CR>

" nerdtree 自动打开 nerdtree, 并将光标停留在右侧编辑区
" autocmd vimenter * NERDTree
" wincmd w
" autocmd VimEnter * wincmd w
" nerdtree 只剩 nerdtree 窗口时关闭 vim
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
"}}}

" Ultisnips -------------------------------------------------------------------{{{
" let g:UltiSnipsExpandTrigger='<c-l>'
" let g:UltiSnipsExpandTrigger='<Tab>'
" let g:UltiSnipsExpandTrigger = "<nop>"
" list 用 c-n, c-p 选择就行了
" 下面的设置默认是 c-j, c-k 用默认的就好了
" 可能冲突了, 有时候会变成 tab
" let g:UltiSnipsJumpForwardTrigger='<c-j>'
" let g:UltiSnipsJumpForwardTrigger='<Tab>'
" let g:UltiSnipsJumpBackwardTrigger='<c-k>'
" let g:snips_author="Codergege"
"}}}


" ale -------------------------------------------------------------------------{{{
" let g:ale_linters_explicit = 1
" let g:ale_completion_delay = 500
" let g:ale_echo_delay = 20
" let g:ale_lint_delay = 500
" let g:ale_echo_msg_format = '[%linter%] %code: %%s'
" let g:ale_lint_on_text_changed = 'normal'
" let g:ale_lint_on_insert_leave = 1
" let g:airline#extensions#ale#enabled = 1

" let g:ale_c_gcc_options = '-Wall -O2 -std=c99'
" let g:ale_cpp_gcc_options = '-Wall -O2 -std=c++14'
" let g:ale_c_cppcheck_options = ''
" let g:ale_cpp_cppcheck_options = ''

" 需要加入 pyls, 不然 python lsp 不起作用.
" Java 使用 ycm 提供的检查
" TODO <19-01-14, Codergege> " Windows 下 tidy 用不了啊...
" \   'rust': ['rls', 'cargo'],
" let g:ale_linters = {
            " \   'python': ['pylint', 'pyls'],
            " \   'java': [],
            " \   'rust': [ 'rls', 'cargo'],
            " \   'javascript': ['prettier'],
            " \   'typescript': ['tsserver'],
            " \   'html': ['tidy'],
            " \   'latex': ['lacheck'],
            " \   'swift': ['swiftlint'],
            " \   'vim':  ['vint'],
            " \   'markdown': ['markdownlint'],
            " \   'c': ['gcc', 'cppcheck'],
            " \   'cpp': ['gcc', 'cppcheck']
            " \}

" html 也可以用 prettier
" c cpp 的 fixers 不起作用
" let g:ale_fixers = {
            " \   '*': ['remove_trailing_lines','trim_whitespace' ],
            " \   'python': ['autopep8'],
            " \   'java': ['google_java_format'],
            " \   'go': ['gofmt'],
            " \   'typescript': ['prettier'],
            " \   'javascript': ['prettier'],
            " \   'html': ['prettier'],
            " \   'c': ['clang-format'],
            " \   'cpp': ['clang-format'],
            " \   'rust': ['rustfmt']
            " \}

" -q -e --language en 是 ale 默认带的. -i 表示 indent.
" let g:ale_html_tidy_options = '-m -i -q -e -language en'
" 使 prettier 使用无分号 style
" let g:ale_javascript_prettier_options = '--no-semi'
" 使用 4 空格的缩进, 而不是 2 空格
" let g:ale_java_google_java_format_options='--aosp'
" TODO <19-01-14, Codergege> " 自己写个插件
"set autoread " 为了配合下面的 google-java-format 工具, 自动加载修改后的格式.
"if WINDOWS()
    "autocmd! BufWritePost *.java
                "\   silent execute '!java -jar c:\Applications\vim81\google-java-format-1.7-all-deps.jar --aosp -r ' expand('%')
"endif
" let g:ale_completion_enabled = 1

" rust 使用 stable 版
" let g:ale_rust_rls_toolchain = 'stable'


""Use :ALEFix to fix
" let g:ale_fix_on_save = 1 "auto Sava
" let g:ale_list_window_size = 5
" 插入新字符后自动关闭 preview window. 这个比较有用.
" let g:ale_close_preview_on_insert = 1


" move between errors - overrides sentence navigation!
" nmap <silent> ) <Plug>(ale_previous_wrap)
" nmap <silent> ( <Plug>(ale_next_wrap)
"}}}
"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                  AutoCmd                                     "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

" Python ----------------------------------------------------------------------{{{
"python with virtualenv support
" py3 << EOF
" import os
" import sys
" import vim
" if 'VIRTUAL_ENV' in os.environ:
"     project_base_dir = os.environ['VIRTUAL_ENV']
"     activate_this_file_path = ''
"     if 'win32' == sys.platform:
"         activate_this_file_path = 'Scripts/activate_this.py'
"     else:
"         activate_this_file_path = 'bin/activate_this.py'
"     activate_this = os.path.join(project_base_dir, activate_this_file_path)
"     # execfile(activate_this, dict(__file__=activate_this))
"     exec(compile(open(activate_this,"rb").read(), activate_this, 'exec'), dict(__file__=activate_this))
" EOF

" 设置 python 文件的 foldmethod=indent
au BufNewFile,BufRead *.py
    \ set tabstop=4 |
    \ set softtabstop=4 |
    \ set shiftwidth=4 |
    \ set textwidth=80 |
    \ set expandtab |
    \ set autoindent |
    \ set fileformat=unix |
    \ set foldmethod=indent |
    \ set foldlevel=99
"}}}

" Java----------------------------------------------------------------------{{{
au BufNewFile,BufRead *.java
    \ set tabstop=4 |
    \ set softtabstop=4 |
    \ set shiftwidth=4 |
    \ set textwidth=80 |
    \ set expandtab |
    \ set autoindent |
    \ set fileformat=unix |
    \ set foldmethod=syntax |
    \ set foldlevel=99
"}}}

" Autopairs ---------------------------------------------------------------{{{
    " 防止按键冲突
    let g:AutoPairsShortcutToggle = ''
    let g:AutoPairsShortcutFastWrap = ''
    let g:AutoPairsShortcutJump = ''
    let g:AutoPairsShortcutBackInsert = ''
" }}}
" leaderF -------------------------------------------------------------------{{{
" 当前项目目录打开文件搜索
let g:Lf_ShortcutF = '<c-p>'
" 打开 Buffer 搜索
let g:Lf_ShortcutB = '<m-p>'
noremap <c-m> :LeaderfMru<cr>
noremap <m-f> :LeaderfFunction!<cr>
noremap <m-p> :LeaderfBuffer<cr>
noremap <m-m> :LeaderfTag<cr>
let g:Lf_StlSeparator = { 'left': '', 'right': '', 'font': '' }

let g:Lf_RootMarkers = ['.project', '.root', '.svn', '.git']
let g:Lf_WorkingDirectoryMode = 'Ac'
let g:Lf_WindowHeight = 0.30
let g:Lf_CacheDirectory = expand('~/.vim/cache')
let g:Lf_ShowRelativePath = 0
let g:Lf_HideHelp = 1
let g:Lf_StlColorscheme = 'powerline'
let g:Lf_PreviewResult = {'Function':0, 'BufTag':0}
" }}}



" Markdown --------------------------------------------------------------------{{{
" => vim-markdown
" let g:vim_markdown_conceal = 1

" 开启 vim 自带的标记隐藏功能, 比如 md 文件中的意大利体, 链接
set conceallevel=2
set concealcursor=""
" Let indentLine use current conceal options
let g:indentLine_conceallevel  = &conceallevel
let g:indentLine_concealcursor = &concealcursor

" 将 md 的折叠样式改为 python-mode 插件类似

"The rules for the cursor position are the same as the gx command.

"]]: go to next header. <Plug>Markdown_MoveToNextHeader

"[[: go to previous header. Contrast with ]c. <Plug>Markdown_MoveToPreviousHeader

"][: go to next sibling header if any. <Plug>Markdown_MoveToNextSiblingHeader

"[]: go to previous sibling header if any. <Plug>Markdown_MoveToPreviousSiblingHeader

"]c: go to Current header. <Plug>Markdown_MoveToCurHeader

"]u: go to parent header (Up). <Plug>Markdown_MoveToParentHeader

" vim-table-mode For Markdown-compatible tables
let g:table_mode_corner='|'

"=> vim-table-mode 相关
" 进入表格模式使用 ,tm (table mode)
" 使用 [count],tt(或 :Tableize{patten} 命令) 将选中的内容生成表格, 用 g:table_mode_delimiter
" 定义表格的分隔符
let g:table_mode_delimiter=";;"
" You can use the following to quickly enable / disable table mode in insert mode by using || or __
function! s:isAtStartOfLine(mapping)
  let text_before_cursor = getline('.')[0 : col('.')-1]
  let mapping_pattern = '\V' . escape(a:mapping, '\')
  let comment_pattern = '\V' . escape(substitute(&l:commentstring, '%s.*$', '', ''), '\')
  return (text_before_cursor =~? '^' . ('\v(' . comment_pattern . '\v)?') . '\s*\v' . mapping_pattern . '\v$')
endfunction

inoreabbrev <expr> <bar><bar>
          \ <SID>isAtStartOfLine('\|\|') ?
          \ '<c-o>:TableModeEnable<cr><bar><space><bar><left><left>' : '<bar><bar>'
inoreabbrev <expr> __
          \ <SID>isAtStartOfLine('__') ?
          \ '<c-o>:silent! TableModeDisable<cr>' : '__'

"=> markdown2ctags 相关
" Add support for markdown files in tagbar.
let g:tagbar_type_markdown = {
    \ 'ctagstype': 'markdown',
    \ 'ctagsbin' : '$HOME/.vim/plugged/markdown2ctags/markdown2ctags.py',
    \ 'ctagsargs' : '-f - --sort=yes --sro=»',
    \ 'kinds' : [
        \ 's:sections',
        \ 'i:images'
    \ ],
    \ 'sro' : '»',
    \ 'kind2scope' : {
        \ 's' : 'section',
    \ },
    \ 'sort': 0,
\ }
" markdown filetype file
au BufRead,BufNewFile *.{md,mdown,mkd,mkdn,markdown,mdwn}
    \ set filetype=markdown |
    \ set foldlevel=100

" 听说 vim8.0 已经支持 markdown 折叠了?
" let g:markdown_folding=1
" let g:vim_markdown_folding_style_pythonic = 1
" let g:vim_markdown_override_foldtext = 0
" let g:vim_markdown_folding_level = 4
" let g:vim_markdown_toc_autofit = 1


" nmap <silent> <Leader>t :Toch<CR>

" This gets rid of the nasty _ italic bug in tpope's vim-markdown
" block $$...$$
syn region math start=/\$\$/ end=/\$\$/
" inline math
syn match math '\$[^$].\{-}\$'

" actually highlight the region we defined as "math"
hi link math Statement
"}}}

" HTML ------------------------------------------------------------------------{{{
"=> Emmet 相关
" let g:user_emmet_mode='a'    "enable all function in all mode.
" Enable just for html/css/markdown
" let g:user_emmet_install_global = 0
" autocmd FileType html,css,markdown EmmetInstall
"To remap the default <C-Y> leader:
"Note that the trailing , still needs to be entered, so the new keymap would be <C-Z>,.
"let g:user_emmet_leader_key='<C-Z>'

"=> surrond.vim 相关  "
" surround_45 是指下划线 _ , 用 yss- 就可以整行两端添加删除线了
autocmd FileType markdown let b:surround_45 = "~~\r~~"

"=> vim-closetag
let g:closetag_filenames = '*.html,*.xhtml,*.phtml'
let g:closetag_xhtml_filenames = '*.xhtml,*.jsx'
let g:closetag_filetypes = 'html,xhtml,phtml'
let g:closetag_xhtml_filetypes = 'xhtml,jsx'
let g:closetag_emptyTags_caseSensitive = 1
let g:closetag_shortcut = '>'
let g:closetag_close_shortcut = '<leader>>'

" *js,*html... 之间不要有空格
" 多命令用 | 隔开
autocmd BufNewFile,BufRead *.js,*.html,*.css,*.jsp,*.xml
    \ set tabstop=2
    \| set softtabstop=2
    \| set shiftwidth=2
    \| set foldmethod=indent
    \| set foldlevel=99
"}}}

" Rust ------------------------------------------------------------------------{{{
" 自动格式化
let g:rustfmt_autosave = 1
"
"}}}

" Asyncrun ------------------------------------------------------------------------{{{
" 自动打开 quickfix window ，高度为 6
let g:asyncrun_open = 6

" 任务结束时候响铃提醒
let g:asyncrun_bell = 1

"F3：打开/关闭底部的 quickfix 窗口
"F4：使用 cmake 生成 Makefile
"F5：单文件：运行
"F6：项目：测试
"F7：项目：编译
"F8：项目：运行
"F9：单文件：编译
" 设置 F3 打开/关闭 Quickfix 窗口
nnoremap <F3> :call asyncrun#quickfix_toggle(6)<cr>
" 最简单的编译单个文件
if WINDOWS()
    nnoremap <silent> <F9> :AsyncRun clang -Wall -O2 "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENOEXT).exe" <cr>
    nnoremap <silent> <F5> :AsyncRun -raw -cwd=$(VIM_FILEDIR) -mode=4 "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
    nnoremap <silent> <F8> :AsyncRun -cwd=<root> -raw make -mode=4 run <cr>
else
    nnoremap <silent> <F9> :AsyncRun clang -Wall -O2 "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
    nnoremap <silent> <F5> :AsyncRun -raw -cwd=$(VIM_FILEDIR) "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
    nnoremap <silent> <F8> :AsyncRun -cwd=<root> -raw make run <cr>
endif
" 运行
nnoremap <silent> <F5> :AsyncRun -raw -cwd=$(VIM_FILEDIR) -mode=4 "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
" 标记项目顶层目录
let g:asyncrun_rootmarks = ['.svn', '.git', '.root', '_darcs', 'build.xml', '.sln']
" 编译整个项目
nnoremap <silent> <F7> :AsyncRun -cwd=<root> make <cr>
" 运行当前项目
" 执行测试
nnoremap <silent> <F6> :AsyncRun -cwd=<root> -raw make test <cr>
" 使用 cmake 更新 makefile
nnoremap <silent> <F4> :AsyncRun -cwd=<root> cmake . <cr>
"}}}


""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"                                  Functional                                  "
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Functional{{{
" 安装 imgcat 在 vim 中预览图片
autocmd BufEnter *.png,*.jpg,*gif exec "! imgcat ".expand("%") | :bw
" autocmd shellcmdpost * if(!exists("b:NERDTree")) :Ntree<cr>

" 设置 gradle 配置文件的折叠方法为 marker
au BufRead,BufNewFile *.{gradle} set foldmethod=marker

" You also want to avoid extraneous whitespace.
" You can have VIM flag that for you so that it’s easy to spot and then remove:
highlight BadWhitespace ctermbg=red guibg=darkred
au BufRead,BufNewFile *.py,*.pyw,*.c,*.h match BadWhitespace /\s\+$/

" ,mt: markdown 转 html
" toc 深度设置为 4: 默认是 3, 只生成到 ### 一级.
" nmap <leader>mt :update<CR>:!pandoc --toc --toc-depth=4 -c pandoc.css -f markdown -t html % -o %:r.html <CR>

""""""""""""""""""""""""""""""""""""""""
"=> 最大化当前窗口{{{
""""""""""""""""""""""""""""""""""""""""
function! Zoom ()
    " check if is the zoomed state (tabnumber > 1 && window == 1)
    if tabpagenr('$') > 1 && tabpagewinnr(tabpagenr(), '$') == 1
        let l:cur_winview = winsaveview()
        let l:cur_bufname = bufname('')
        tabclose

        " restore the view
        if l:cur_bufname == bufname('')
            call winrestview(cur_winview)
        endif
    else
        tab split
    endif
endfunction

nnoremap <leader>z :call Zoom()<CR>
"}}}

""""""""""""""""""""""""""""""""""""""""
"=> 用浏览器打开当前文件{{{
""""""""""""""""""""""""""""""""""""""""
if WINDOWS()
    function! ViewInBrowser(name)
        let file = expand("%:p")
        exec ":update " . file
        " 要求加入环境变量哦
        let l:browsers = {
            \"cr":"chrome",
            \"ff":"firefox",
        \}
        let htdocs='E:\\apmxe\\htdocs\\'
        let strpos = stridx(file, substitute(htdocs, '\\\\', '\', "g"))
        if strpos == -1
           exec ":silent !start ". l:browsers[a:name] ." file://" . file
        else
            let file=substitute(file, htdocs, "http://127.0.0.1:8090/", "g")
            let file=substitute(file, '\\', '/', "g")
            exec ":silent !start ". l:browsers[a:name] file
        endif
    endfunction
elseif OSX()
    " 在浏览器预览 for Mac
    function! ViewInBrowser(name)
        let file = expand("%:p")
        " TODO <18-12-11, Codergege> " 能不能运行要先看看
        let l:browsers = {
            \"cr":"open -a /Applications/Google Chrome.app",
            \"ff":"open -a /Applications/Firefox.app",
        \}
        let htdocs='/Users/leon1/'
        let strpos = stridx(file, substitute(htdocs, '\\\\', '\', "g"))
        let file = '"'. file . '"'
        exec ":update " .file
        "echo file .' ## '. htdocs
        if strpos == -1
            exec ":silent ! ". l:browsers[a:name] ." file://". file
        else
            let file=substitute(file, htdocs, "http://127.0.0.1:8090/", "g")
            let file=substitute(file, '\\', '/', "g")
            exec ":silent ! ". l:browsers[a:name] file
        endif
    endfunction
else
    " TODO <18-12-11, Codergege> " Linux
endif

if WINDOWS()
    nmap <Leader>ff :call ViewInBrowser("ff")<cr>
    nmap <Leader>gg :call ViewInBrowser("cr")<cr>
elseif OSX()
    nmap <Leader>gg :!open %<cr>
else
    " TODO <18-12-26, Codergege> "linux
endif
"}}}

" 用 typora 浏览{{{
function! Typora()
    " set lines=25 columns=85
    " exec ":winpos 360 0"
    exec ":silent !start ". "typora" ." " . expand("%:p")
endfunction
if WINDOWS()
    " dos 下使用
    " nmap <Leader>pp :!typora %<cr>
    " git bash 下使用
    " nmap <Leader>pp :exec ":silent !start ". "typora" ." " . expand("%:p")<CR>
    nmap <Leader>pp :call Typora()<CR>
elseif OSX()
    nmap <Leader>pp :!open %<cr>
    " nmap <Leader>pp :exe ':silent !open -a /Applications/Typora.app %'<CR>
else
    " TODO <18-12-11, Codergege> " Linux
    nmap <Leader>pp :!open %<cr>
endif
"}}}

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Quickly Run{{{
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
map <Leader>rr :call CompileRunGcc()<CR>
" map <Leader>rc :call CargoRun()<CR>
map <Leader>tt :call CargoTest()<CR>

func! CargoRun()
    exec "w"
    if &filetype == 'rust'
        :!cargo run
    endif
endfunc

func! CargoTest()
    exec "w"
    if &filetype == 'rust'
        :!cargo test
    endif
endfunc


func! CompileRunGcc()
    exec "w"
    if &filetype == 'c'
        " exec '!g++ % -o %<'
        exec '!clang % -o %<.exe'
        if !WINDOWS()
            exec '!time ./%<'
        else
            exec "! %<.exe"
        endif
    elseif &filetype == 'cpp'
        " exec '!g++ % -o %<'
        exec '!clang % -o %<.exe'
        if !WINDOWS()
            exec '!time ./%<'
        else
            exec "! %<.exe"
        endif
    elseif &filetype == 'python'
        " exec '!time python %'
        exec '!python %'
    elseif &filetype == 'go'
        exec '!go run %'
    elseif &filetype == 'sh'
        :!time bash %
    elseif &filetype == 'java'
        :!javac %&&java %:r
    elseif &filetype == 'javascript'
        :!node %
    elseif &filetype == 'rust'
        " :RustRun
        :call CargoRun()
    endif
endfunc
"}}}

" 快速配置 snippets{{{
" 1. all.snippets
" nnoremap <leader>na :vsplit ~/.vim/UltiSnips/all.snippets<cr>
" 2. cpp.snippets
" nnoremap <leader>nc :vsplit ~/.vim/UltiSnips/cpp.snippets<cr>
" 3. markdown.snippets
" nnoremap <leader>nm :vsplit ~/.vim/UltiSnips/markdown.snippets<cr>
" 4. html.snippets
" nnoremap <leader>nt :vsplit ~/.vim/UltiSnips/html.snippets<cr>
" 5. python.snippets
" nnoremap <leader>np :vsplit ~/.vim/UltiSnips/python.snippets<cr>
" 5. rust.snippets
" nnoremap <leader>nr :vsplit ~/.vim/UltiSnips/rust.snippets<cr>
"}}}

"}}}
